#pragma once

#include <iostream>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include "ThreadPool.hpp"
#include "Daemon.hpp"

using namespace std;

// uint16_t defaultport = 8888;
string defaultip = "0.0.0.0";
int backlog = 11;

enum
{
    ListenSock_Create = 1,
    Bind_Create,
    Listen_Create
};

class TcpServer
{
public:
    TcpServer(uint16_t port, string ip = defaultip)
        : _port(port), _ip(ip), _listensockfd(-1)
    {
        ;
    }

    void Init()
    {
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            lg(Fatal, "listensockfd create fail,errno:%d,message:%s", errno, strerror(errno));
            exit(ListenSock_Create);
        }
        lg(Info, "listensockfd create success,listensockfd:%d", _listensockfd);

         // 防止偶发性的服务器无法进行立即重启
        int opt = 1;
        setsockopt(_listensockfd, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));

        sockaddr_in server;
        server.sin_family = AF_INET;
        inet_aton(_ip.c_str(), &server.sin_addr);
        server.sin_port = htons(_port);

        int bindRes = bind(_listensockfd, (sockaddr *)&server, sizeof(server));
        if (bindRes < 0)
        {
            lg(Fatal, "Server bind fail,errno:%d,message:%d", errno, strerror(errno));
            exit(Bind_Create);
        }
        lg(Info, "Server bind success,listensockfd:%d", _listensockfd);

        // 不同于Udp的地方，需要listen
        //  TCP是面向连接的，服务器一般是比较“被动的”，服务器一直处于一种，一直在等待连接到来的状态
        int listenRes = listen(_listensockfd, backlog);
        if (listenRes < 0)
        {
            lg(Fatal, "Server listen fail,errno:%d,message:%d", errno, strerror(errno));
            exit(Listen_Create);
        }
        lg(Info, "Server listen success,listensockfd:%d", _listensockfd);
    }

    void Run()
    {
        lg.record = CLASSIFYFILE;
        Daemon();
        // //防止出现客户端的文件描述符关掉后，操作系统直接杀死了服务端的进程
        // //就好像你不能客户退出了，你服务器直接关了
        // signal(SIGPIPE,SIG_IGN);
        
        ThreadPool<Task>::GetInstance()->start();
        while (true)
        {
            lg(Info, "server start to accept");

            sockaddr_in client;
            memset(&client, 0, sizeof(client));
            socklen_t len = sizeof(client);

            // 返回值是一个文件描述符，这个sockfd专门用来进行通信
            //_listensockfd，专门用来监听
            int sockfd = accept(_listensockfd, (sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Warning, "server accept client fail,errno:%d,message:%s", errno, strerror(errno));
                continue;
            }
            lg(Info, "server accept success,sockfd:%d", sockfd);

            char clientIp[1024];
            inet_ntop(AF_INET, &(client.sin_addr), clientIp, sizeof(clientIp));
            uint16_t clientPort = ntohs(client.sin_port);

            // 单进程版本
            //  Service(sockfd, clientIp, clientPort);
            //  close(sockfd);

            // 多线程版本
            Task t(sockfd, clientIp, clientPort);
            ThreadPool<Task>::GetInstance()->push(t);
        }
    }

    void Service(int sockfd, const string &clientIp, const uint16_t clientPort)
    {
        char buffer[1024];
        int n = read(sockfd, buffer, sizeof(buffer));
        if (n > 0)
        {
            buffer[n] = '\0';
            string message = "client say# ";
            message += buffer;

            write(sockfd, message.c_str(), message.size());
        }
        else if (n == 0)
        {
            lg(Info, "%s:%d,has exited\n", clientIp.c_str(), clientPort);
        }
        else if (n < 0)
        {
            lg(Warning, "Read Nothing form %s:%d\n", clientIp.c_str(), clientPort);
        }
    }

private:
    int _listensockfd;
    uint16_t _port;
    string _ip;
};